<template>
	<div class="monitor-rediscache-container">
		<el-row>
			<el-col :xs="24" :sm="24" :md="6" :lg="6" :xl="6" class="mb15">
				<el-card shadow="hover" header="命令行执行总次数">
					<div style="height: 350px" ref="cmdstatCallsOptionsRef"></div>
				</el-card>
			</el-col>
			<el-col :xs="24" :sm="24" :md="6" :lg="6" :xl="6" class="mb15">
				<el-card shadow="hover" header="CPU执行命令行消耗时长(单位微秒)">
					<div style="height: 350px" ref="cmdstatUsecOptionsRef"></div>
				</el-card>
			</el-col>
			<el-col :xs="24" :sm="24" :md="6" :lg="6" :xl="6" class="mb15">
				<el-card shadow="hover" header="CPU执行命令行平均消耗时长(单位微秒)">
					<div style="height: 350px" ref="cmdstatUsecPerCallOptionsRef"></div>
				</el-card>
			</el-col>
			<el-col :xs="24" :sm="24" :md="6" :lg="6" :xl="6" class="mb15">
				<el-card shadow="hover" header="内存消耗情况">
					<div style="height: 350px" ref="memoryUseOptionsRef"></div>
				</el-card>
			</el-col>
		</el-row>
		<el-row>
			<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb15">
				<el-card shadow="hover">
					<el-descriptions style="overflow-x: auto;" title="Redis缓存健康参数" :column="3" border v-if="!isShowMoreInfo">
						<template v-slot:extra>
							<el-link type="primary" :underline="false" @click="isShowMoreInfo=true">更多</el-link>
						</template>
						<el-descriptions-item>
							<template v-slot:label>Redis版本</template>
							{{redisHealthInfo.redis_version}}
						</el-descriptions-item>
						<el-descriptions-item>
							<template v-slot:label>操作系统</template>
							{{redisHealthInfo.os}}
						</el-descriptions-item>
						<el-descriptions-item>
							<template v-slot:label>系统架构</template>
							{{redisHealthInfo.arch_bits}}
						</el-descriptions-item>
						<el-descriptions-item>
							<template v-slot:label>运行模式</template>
							{{redisHealthInfo.redis_mode}}
						</el-descriptions-item>
						<el-descriptions-item>
							<template v-slot:label>TCP端口</template>
							{{redisHealthInfo.tcp_port}}
						</el-descriptions-item>
						<el-descriptions-item>
							<template v-slot:label>事件处理机制</template>
							{{redisHealthInfo.multiplexing_api}}
						</el-descriptions-item>
						<el-descriptions-item>
							<template v-slot:label>Redis进程PID</template>
							{{redisHealthInfo.process_id}}
						</el-descriptions-item>
						<el-descriptions-item>
							<template v-slot:label>启动总时长(秒)</template>
							{{redisHealthInfo.uptime_in_seconds}}
						</el-descriptions-item>
						<el-descriptions-item>
							<template v-slot:label>启动总时长(天)</template>
							{{redisHealthInfo.uptime_in_days}}
						</el-descriptions-item>
						<el-descriptions-item>
							<template v-slot:label>已连接客户端数量</template>
							{{redisHealthInfo.connected_clients}}
						</el-descriptions-item>
						<el-descriptions-item>
							<template v-slot:label>服务器吞吐</template>
							{{redisHealthInfo.instantaneous_input_kbps}} / {{redisHealthInfo.instantaneous_output_kbps}}
						</el-descriptions-item>
						<el-descriptions-item>
							<template v-slot:label>服务器QPS</template>
							{{redisHealthInfo.instantaneous_ops_per_sec}}
						</el-descriptions-item>
						<el-descriptions-item>
							<template v-slot:label>分配内存总量</template>
							{{redisHealthInfo.used_memory_human}}
						</el-descriptions-item>
						<el-descriptions-item>
							<template v-slot:label>内存消耗峰值</template>
							{{redisHealthInfo.used_memory_peak_human}}
						</el-descriptions-item>
						<el-descriptions-item>
							<template v-slot:label>内存碎片比例</template>
							{{redisHealthInfo.mem_fragmentation_ratio}}
						</el-descriptions-item>
						<el-descriptions-item>
							<template v-slot:label>是否开启AOF</template>
							{{redisHealthInfo.aof_enabled}}
						</el-descriptions-item>
						<el-descriptions-item>
							<template v-slot:label>是否成功持久化RDB</template>
							{{redisHealthInfo.rdb_last_bgsave_status}}
						</el-descriptions-item>
						<el-descriptions-item>
							<template v-slot:label>缓存命中次数</template>
							{{redisHealthInfo.keyspace_hits}}
						</el-descriptions-item>
					</el-descriptions>
					<el-descriptions style="overflow-x: auto;" title="Redis缓存健康参数" :column="3" border v-else>
						<template v-slot:extra>
							<el-link type="primary" :underline="false" @click="isShowMoreInfo=false">收起</el-link>
						</template>
						<el-descriptions-item v-for="(value, key) in redisHealthInfo" :key="key">
							<template v-slot:label>{{key}}</template>
							{{value}}
						</el-descriptions-item>
					</el-descriptions>
				</el-card>
			</el-col>
		</el-row>
	</div>
</template>

<script lang="ts">
import { ref, toRefs, reactive, onMounted, nextTick, onActivated, watch } from 'vue';
import * as echarts from 'echarts';
import { storeToRefs } from 'pinia';
import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes';
import { getRedisCacheHealth } from '/@/api/monitor/rediscache/index';
export default {
	name: 'rediscache',
	setup() {
		const cmdstatCallsOptionsRef = ref();
		const cmdstatUsecOptionsRef = ref();
		const cmdstatUsecPerCallOptionsRef = ref();
		const memoryUseOptionsRef = ref();
		const storesTagsViewRoutes = useTagsViewRoutes();
		const { isTagsViewCurrenFull } = storeToRefs(storesTagsViewRoutes);
		const state = reactive({
			isShowMoreInfo: false,
			redisHealthInfo: {},
			myCharts: [],
		});
		const loadRedisHealthInfo = async () => {
			await getRedisCacheHealth().then((res) => {
				if(res.code == 0){
					state.redisHealthInfo = res.data;
				}
			});
		}
		const initCmdstatChart = (name: string, dom: HTMLElement, index: number) => {
			const options = {
				tooltip: {
					trigger: 'item',
					formatter: '{b} : {c} ({d}%)'
				},
				series: [{
					name: name,
					type: 'pie',
					radius: '55%',
					roseType: 'angle',
					data: [
						//{value: Number(getCmdstatOptionsByKey('cmdstat_auth', index)), name: 'auth'},
						//{value: Number(getCmdstatOptionsByKey('cmdstat_client', index)), name: 'client'},
						//{value: Number(getCmdstatOptionsByKey('cmdstat_cluster', index)), name: 'cluster'},
						//{value: Number(getCmdstatOptionsByKey('cmdstat_command', index)), name: 'command'},
						//{value: Number(getCmdstatOptionsByKey('cmdstat_psync', index)), name: 'psync'},
						//{value: Number(getCmdstatOptionsByKey('cmdstat_replconf', index)), name: 'replconf'},
						{value: Number(getCmdstatOptionsByKey('cmdstat_del', index)), name: 'del'},
						{value: Number(getCmdstatOptionsByKey('cmdstat_get', index)), name: 'get'},
						{value: Number(getCmdstatOptionsByKey('cmdstat_hdel', index)), name: 'hdel'},
						{value: Number(getCmdstatOptionsByKey('cmdstat_hexists', index)), name: 'hexists'},
						{value: Number(getCmdstatOptionsByKey('cmdstat_hget', index)), name: 'hget'},
						{value: Number(getCmdstatOptionsByKey('cmdstat_hkeys', index)), name: 'hkeys'},
						{value: Number(getCmdstatOptionsByKey('cmdstat_hlen', index)), name: 'hlen'},
						{value: Number(getCmdstatOptionsByKey('cmdstat_hscan', index)), name: 'hscan'},
						{value: Number(getCmdstatOptionsByKey('cmdstat_hset', index)), name: 'hset'},
						{value: Number(getCmdstatOptionsByKey('cmdstat_info', index)), name: 'info'},
						{value: Number(getCmdstatOptionsByKey('cmdstat_keys', index)), name: 'keys'},
						{value: Number(getCmdstatOptionsByKey('cmdstat_ping', index)), name: 'ping'},
						{value: Number(getCmdstatOptionsByKey('cmdstat_scan', index)), name: 'scan'},
						{value: Number(getCmdstatOptionsByKey('cmdstat_select', index)), name: 'select'},
						{value: Number(getCmdstatOptionsByKey('cmdstat_set', index)), name: 'set'},
						{value: Number(getCmdstatOptionsByKey('cmdstat_setex', index)), name: 'setex'},
						{value: Number(getCmdstatOptionsByKey('cmdstat_ttl', index)), name: 'ttl'},
						{value: Number(getCmdstatOptionsByKey('cmdstat_type', index)), name: 'type'},
					],
				}]
			};
			const myChart = echarts.init(dom);
			myChart.setOption(options);
			state.myCharts.push(myChart);
		}
		
		const initMemoryChart = () => {
			let memory = Number(state.redisHealthInfo.used_memory) / 1024 / 1024;
			let maxMemory = memory < 1024 ? 1024 : memory < 2048 ? 2048 : memory < 4096 ? 4096 : 8192;
			const options = {
				series: [{
					type: 'gauge',
					radius: '100%',
					max: maxMemory,
					splitNumber: 8,
					axisLine: {
						lineStyle: {
							width: 30,
							color: [
								[0.3, '#67e0e3'],
								[0.7, '#37a2da'],
								[1, '#fd666d']
							]
						}
					},
					pointer: {
						itemStyle: {
							color: 'auto'
						}
					},
					axisTick: {
						distance: -30,
						length: 8,
						lineStyle: {
							color: '#fff',
							width: 2
						}
					},
					splitLine: {
						distance: -30,
						length: 30,
						lineStyle: {
							color: '#fff',
							width: 4
						}
					},
					axisLabel: {
						color: 'auto',
						distance: 40,
						fontSize: 10
					},
					detail: {
						valueAnimation: true,
						formatter: '{value} MB',
						color: 'auto',
						fontSize: 20
					},
					data: [{
						value: memory.toFixed(2),
					}]
				}]
			};
			const myChart = echarts.init(memoryUseOptionsRef.value);
			myChart.setOption(options);
			state.myCharts.push(myChart);
		}
		
		/**
		 * @param {string} key 键值
		 * @param {number} index 序号 0,1,2,3
		 */
		const getCmdstatOptionsByKey = (key: string, index: number) => {
			let value = state.redisHealthInfo[key];
			if(value){
				let values = value.match(/calls=(\d+),usec=(\d+),usec_per_call=(\d+\.\d+)/);
				return values[index];
			}
			return 0;
		}
		// 批量设置 echarts resize
		const initEchartsResizeFun = () => {
			nextTick(() => {
				for (let i = 0; i < state.myCharts.length; i++) {
					state.myCharts[i].resize();
				}
			});
		};
		// 批量设置 echarts resize
		const initEchartsResize = () => {
			window.addEventListener('resize', initEchartsResizeFun);
		};
		// 由于页面缓存原因，keep-alive
		onActivated(() => {
			initEchartsResizeFun();
		});
		// 监听 vuex 中的 tagsview 开启全屏变化，重新 resize 图表，防止不出现/大小不变等
		watch(
			() => isTagsViewCurrenFull.value,
			() => {
				initEchartsResizeFun();
			}
		);
		// 页面加载时
		onMounted(async () => {
			await loadRedisHealthInfo();
			initCmdstatChart('命令行执行总次数', cmdstatCallsOptionsRef.value, 1);
			initCmdstatChart('CPU执行命令行消耗时长(单位微秒)', cmdstatUsecOptionsRef.value, 2);
			initCmdstatChart('CPU执行命令行平均消耗时长(单位微秒)', cmdstatUsecPerCallOptionsRef.value, 3);
			initMemoryChart();
			initEchartsResize();
		});
		return {
			cmdstatCallsOptionsRef,
			cmdstatUsecOptionsRef,
			cmdstatUsecPerCallOptionsRef,
			memoryUseOptionsRef,
			...toRefs(state),
		};
	},
};
</script>